<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>4.promise练习2</title>
</head>
<body>
    
</body>
<script>
    const PROMISE_STATUS_PENDING = 'pending'
    const PROMISE_STATUS_FULFILLED = 'fulfilled'
    const PROMISE_STATUS_REJECTED = 'rejected'

    class MyPromise {
        constructor(executor) {
            this.status = PROMISE_STATUS_PENDING
            this.result = undefined
            this.reason = undefined
            this.onfulfilledFns = []
            this.onRejectedFns = []            

            const resolve = (result) => {
                if(this.status !== PROMISE_STATUS_PENDING) return
                this.status = PROMISE_STATUS_FULFILLED
                this.result = result
                this.onfulfilledFns.forEach(fn => fn())
            }

            const reject = (reason) => {
                if(this.status !== PROMISE_STATUS_PENDING) return
                this.status = PROMISE_STATUS_REJECTED
                this.reason = reason
                this.onRejectedFns.forEach(fn => fn())
            }

            executor(resolve, reject)
        }

        then(onFulfilled, onRejected) {
            return new MyPromise((resolve, reject) => {
                if(this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
                    let result = onFulfilled(this.result)
                    resolve(result)
                }
                if(this.status === PROMISE_STATUS_REJECTED && onRejected) {
                    let resaon = onRejected(this.reason)
                    reject(resaon)
                }
                if(this.status === PROMISE_STATUS_PENDING) {
                    if(onFulfilled) {
                        this.onfulfilledFns.push(() => {
                            let result = onFulfilled(this.result)
                            resolve(result)
                        })
                    }
                    if(onRejected) {
                        this.onRejectedFns.push(() => {
                            let resaon = onRejected(this.reason)
                            reject(resaon)
                        })
                    }
                }
            })

        }

        catch(onRejected) {
            return this.then(undefined, onRejected)
        }

        finally(onFinally) {
            this.then(() => {
                onFinally()
            },() => {
                onFinally()
            })
        }

        static resolve(result){
            return new MyPromise(resolve => {resolve(result)})
        }

        static reject(reason) {
            return new MyPromise((undefined, reject) => {reject(reason)})
        }

        static all(promises) {
            return new MyPromsie((resolve, reject) => {
                const values = []
                promises.forEach(promise => {
                    promise.then(
                        res => {
                            values.push(promise)
                            if(values.length === promises.length) {
                                resolve(res)
                            }
                        },
                        err => {
                            reject(err)
                        }
                    )
                })
            })
        }   
        
        static race(promises) {
            return new MyPromise((resolve, reject) => {
                promises.forEach(promise => {
                    promise.then(res => {
                        resolve(res)
                    },err => {
                        reject(err)
                    })
                })
            })
        }
    }

    // let p = new Promise((resolve, reject) => {
    //     resolve('哈哈哈')
    // }).then(res => {
    //     console.log(res)
    // })

    let p1 = new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve('你好呀')
        })
    }).then(res => {
        console.log('res:', res)
    })

    console.log('p1:', p1)
</script>
</html>